package com.ruoyi.web.controller.pv;

import java.util.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import com.doudou.core.container.ListUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.doudou.core.lang.Option;
import com.ruoyi.pv.domain.*;
import com.ruoyi.pv.domain.vo.PvAppointRecordNumVo;
import com.ruoyi.pv.service.IPvAppointRecordService;
import com.ruoyi.pv.service.IPvHolidayService;
import com.ruoyi.pv.service.IPvTrainingClassService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.pv.service.IPvAppointService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;

/**
 * 实训预约Controller
 *
 * @author zzx
 * @date 2023-04-22
 */
@Api("实训预约")
@RestController
@RequestMapping("/pv/appoint")
public class PvAppointController extends BaseController {

    @Resource private IPvAppointService pvAppointService;
    @Resource private IPvHolidayService pvHolidayService;
    @Resource private IPvTrainingClassService pvTrainingClassService;
    @Resource private IPvAppointRecordService appointRecordService;


    /**
     * 查询实训预约列表
     */
    @GetMapping("/list-applet")
    @ApiOperation("查询实训预约列表")
    public TableDataInfo listApplet(PvAppoint pvAppoint) {
        pvAppoint.setDeptId(getDeptId());
        startPage();
        List<PvAppoint> list = pvAppointService.selectPvAppointList(pvAppoint);
        //如果roomId不存在，说明是第一次调用，根据roomid去重
        if (ObjectUtil.isEmpty(pvAppoint.getRoomId())) {
            HashMap<Long, PvAppoint> map = new HashMap<>();
            for (PvAppoint appoint : list) {
                map.put(appoint.getRoomId(), appoint);
            }
            list = ListUtil.list(true);
            list.addAll(map.values());
        }
        /* 过滤数据
         * 1、提前预约时间:算出当前时间是否在 开始时间加上提前预约时间之内,不在则不返回
         * 2、TODO 每一个时间段添加上已预约人数，根据时间去匹配
         * 3、返回开始时间和截止时间的范围
         */
        List<PvAppoint> resultList = ListUtil.list(true);
        DateTime dateTime = new DateTime();//当前时间
        for (PvAppoint appoint : list) {
            Date beginDate = appoint.getBeginDate();
            Date endDate = appoint.getEndDate();
            //过滤不在提前预约时间范围内
            DateTime endDateTime = DateTime.of(endDate);//结束时间
            DateTime isForwardDate = DateTime.of(beginDate).offsetNew(DateField.DAY_OF_MONTH, appoint.minusForwardDate());//提前预约时间=>考试开始时间加上提前天数
            if (dateTime.isIn(isForwardDate, endDateTime)) {//在提前预约时间后 and 在考试结束时间前
                Set<String> holidays = pvHolidayService.getAllHoliday().keySet();
                //整合时间范围
                for (DateTime time : DateUtil.rangeToList(beginDate, endDate, DateField.DAY_OF_YEAR)) {
                    if (!holidays.contains(time.toDateStr())) {//排除节假日
                        appoint.addRange(time.toDateStr());
                    }
                }
                resultList.add(appoint);
            }
        }
        return getDataTable(resultList);
    }

    /**
     * 查询实训预约列表
     */
    @GetMapping("/list")
    @ApiOperation("查询实训预约列表")
    public TableDataInfo list(PvAppoint pvAppoint) {
        pvAppoint.setDeptId(getDeptId());
        startPage();
        List<PvAppoint> list = pvAppointService.selectPvAppointList(pvAppoint);
        return getDataTable(list);
    }

    /**
     * 导出实训预约列表
     */
    @PreAuthorize("@ss.hasPermi('appoint:appoint:export')")
    @Log(title = "实训预约", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, PvAppoint pvAppoint) {
        pvAppoint.setDeptId(getDeptId());
        List<PvAppoint> list = pvAppointService.selectPvAppointList(pvAppoint);
        ExcelUtil<PvAppoint> util = new ExcelUtil<PvAppoint>(PvAppoint.class);
        util.exportExcel(response, list, "实训预约数据");
    }

    /**
     * 获取实训预约详细信息
     */
    @PreAuthorize("@ss.hasPermi('appoint:appoint:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(pvAppointService.selectPvAppointById(id));
    }

    /**
     * 新增实训预约
     */
    @PreAuthorize("@ss.hasPermi('appoint:appoint:add')")
    @Log(title = "实训预约", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody PvAppoint pvAppoint) {
        Long deptId = getDeptId();
        //先查询是否有班级
        PvTrainingClass clazz = pvTrainingClassService.selectPvTrainingYearLast(deptId);
        if (clazz == null) {
            return AjaxResult.error("没有可添加的班级，请先添加班级");
        }
        pvAppoint.setDeptId(deptId);
        pvAppoint.setClassId(clazz.getId());
        return toAjax(pvAppointService.insertPvAppoint(pvAppoint));
    }

    /**
     * 修改实训预约
     */
    @PreAuthorize("@ss.hasPermi('appoint:appoint:edit')")
    @Log(title = "实训预约", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody PvAppoint pvAppoint) {
        pvAppoint.setDeptId(getDeptId());
        return toAjax(pvAppointService.updatePvAppoint(pvAppoint));
    }

    /**
     * 删除实训预约
     */
    @PreAuthorize("@ss.hasPermi('appoint:appoint:remove')")
    @Log(title = "实训预约", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(pvAppointService.deletePvAppointByIds(ids));
    }

    /**
     * 发送短信通知-人数
     */
    @PreAuthorize("@ss.hasPermi('appoint:appoint:edit')")
    @Log(title = "发送短信通知", businessType = BusinessType.DELETE)
    @PostMapping("/smsSend-people-count")
    public AjaxResult remove(@RequestBody JSONObject body) {
        return success(pvAppointService.smsSendPeopleCount(body.getBeanList("classId", Long.class)));
    }

    /**
     * 发送短信通知
     */
    @PreAuthorize("@ss.hasPermi('appoint:appoint:edit')")
    @Log(title = "发送短信通知", businessType = BusinessType.DELETE)
    @PostMapping("/smsSend/{id}")
    public AjaxResult remove(@PathVariable Long id, @RequestBody JSONObject body) {
        pvAppointService.smsSend(id, body.getStr("time"), body.getBeanList("classId", Long.class));
        return success();
    }

    //------------------------ 小程序使用预约查询接口 ---------------------------------------

    /**
     * 查询可以预约的场地
     */
    @GetMapping("/get-appoint-room")
    public AjaxResult getAppointRoom() {
        return success(Option.of(pvAppointService.selectPvAppointRoomList()).get(ListUtil.list(false)));
    }

    /**
     * 根据场地查询可以预约的预约数据
     */
    @GetMapping("/get-appoint-program/{room_id}")
    public AjaxResult getAppointProgram(@PathVariable("room_id") Long roomId) {
        Option<List<PvAppoint>> optional = Option.of(pvAppointService.selectPvAppointList(PvAppoint.builder().roomId(roomId).build()));
        optional.ifNotNull(a -> {
            a.forEach(item -> item.setPvAppointTimeList(null));
        });
        return success(optional.get(ListUtil.list(false)));
    }

    /**
     * 根据选择的预约编号查询预约信息，如果当前时间在预约范围内，返回可以预约日期范围
     */
    @GetMapping("/get-appoint-dateRange/{id}")
    public AjaxResult getAppointDateRange(@PathVariable("id") Long id) {
        Option<PvAppoint> optional = Option.of(pvAppointService.selectPvAppointById(id));
        optional.ifNotNull(appoint -> {
            DateTime now = DateTime.now();//当前时间
            Date beginDate = appoint.getBeginDate();
            Date endDate = appoint.getEndDate();
            //过滤不在提前预约时间范围内
            DateTime forwardDate = DateTime.of(beginDate).offsetNew(DateField.DAY_OF_MONTH, appoint.minusForwardDate());//结束考试时间=>考试开始时间加上提前天数
            if (now.isIn(forwardDate, endDate)) {//在提前预约时间后 and 在考试结束时间前
                Set<String> allHoliday = pvHolidayService.getAllHoliday().keySet();
                //整合时间范围
                DateUtil.rangeToList(beginDate, endDate, DateField.DAY_OF_YEAR).forEach(time -> {
                    if (!allHoliday.contains(time.toDateStr())) {//排除节假日
                        appoint.addRange(time.toDateStr());
                    }
                });
            }
        });
        return success(optional.get(new PvAppoint()).getDateRange());
    }

    /**
     * 根据选择的预约编号查询预约信息，根据用户选择的时间查询每个时间段剩余的可预约的名额
     */
    @GetMapping("/get-appoint-times/{id}")
    public AjaxResult getAppointDateRange(@PathVariable("id") Long id, @RequestParam("date") String date) {
        PvAppoint appoint = pvAppointService.selectPvAppointById(id);
        //查询预约人数
        Map<Long, PvAppointRecordNumVo> recordNumVos = appointRecordService.selectPvAppointRecordCountByAppointAndDateGroupByTime(id, date);
        List<PvAppointTime> pvAppointTimeList = appoint.getPvAppointTimeList();
        PvAppointRecordNumVo zeroBean = PvAppointRecordNumVo.builder().num(0).build();
        for (PvAppointTime time : pvAppointTimeList) {
            Option<PvAppointRecordNumVo> numOptional = Option.of(recordNumVos.get(time.getId()));
            PvAppointRecordNumVo numVo = numOptional.get(zeroBean);//如果为空返回一个num为0的对象
            time.setNum(appoint.getQuantity() - numVo.getNum());//容量减去已预约人数
        }
        return success(pvAppointTimeList);
    }
}










